import json
import logging
import os
from pathlib import Path
from typing import Any

from oauth2client.client import OAuth2Credentials
from pydrive2.auth import GoogleAuth
from pydrive2.fs import GDriveFileSystem

from unstract.connectors.exceptions import ConnectorError
from unstract.connectors.filesystems.google_drive.constants import GDriveConstants
from unstract.connectors.filesystems.unstract_file_system import UnstractFileSystem
from unstract.connectors.gcs_helper import GCSHelper

logger = logging.getLogger(__name__)


class GoogleDriveFS(UnstractFileSystem):
    # Settings dict should contain the following:
    # {
    #   "access_token": "<access_token>",
    #   "refresh_token": "<refresh_token>",
    #   "token_expiry": "<token_expiry (calculated)>"
    # }
    def __init__(self, settings: dict[str, Any]):
        super().__init__("GoogleDrive")
        client_secrets = json.loads(
            GCSHelper().get_secret("google_drive_client_secret")
        )
        self.oauth2_credentials = {
            "client_id": client_secrets["web"]["client_id"],
            "client_secret": client_secrets["web"]["client_secret"],
            "token_uri": client_secrets["web"]["token_uri"],
            "user_agent": None,
            "invalid": False,
            "access_token": settings["access_token"],
            "refresh_token": settings["refresh_token"],
            GDriveConstants.TOKEN_EXPIRY: settings[GDriveConstants.TOKEN_EXPIRY],
        }
        gauth = GoogleAuth(
            settings_file=f"{os.path.dirname(__file__)}/static/settings.yaml",
            settings={"client_config": client_secrets["web"]},
        )
        gauth.credentials = OAuth2Credentials.from_json(
            json_data=json.dumps(self.oauth2_credentials)
        )
        self.drive = GDriveFileSystem(path="root", google_auth=gauth)

    @staticmethod
    def get_id() -> str:
        return "gdrive|3ac4b966-9136-4261-944a-bdbfc51cd21c"

    @staticmethod
    def get_name() -> str:
        return "Google Drive"

    @staticmethod
    def get_description() -> str:
        return "Access files in your Google Drive"

    @staticmethod
    def get_icon() -> str:
        return "/icons/connector-icons/Google%20Drive.png"

    @staticmethod
    def get_json_schema() -> str:
        f = open(f"{os.path.dirname(__file__)}/static/json_schema.json")
        schema = f.read()
        f.close()
        return schema

    @staticmethod
    def requires_oauth() -> bool:
        return True

    @staticmethod
    def python_social_auth_backend() -> str:
        return "google-oauth2"

    @staticmethod
    def can_write() -> bool:
        return True

    @staticmethod
    def can_read() -> bool:
        return True

    def get_fsspec_fs(self) -> GDriveFileSystem:
        return self.drive

    def test_credentials(self) -> bool:
        """To test credentials for Google Drive."""
        is_dir = False
        try:
            is_dir = bool(self.get_fsspec_fs().isdir("root"))
        except Exception as e:
            raise ConnectorError(
                f"Error from Google Drive while testing connection: {str(e)}"
            ) from e
        if not is_dir:
            raise ConnectorError(
                "Unable to connect to Google Drive, "
                "please check the connection settings."
            )
        return True

    @staticmethod
    def get_connector_root_dir(input_dir: str, **kwargs: Any) -> str:
        """Get roor dir of gdrive."""
        root_path = kwargs.get("root_path")
        if root_path is None:
            raise ValueError("root_path is required to get root_dir for Google Drive")
        input_dir = str(Path(root_path, input_dir.lstrip("/")))
        return f"{input_dir.strip('/')}/"
